package com.qingxin.sys.service;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.stereotype.Service;

import com.qingxin.sys.dao.IBaseDao;
import com.qingxin.sys.dao.JdbcSupport;
import com.qingxin.sys.dao.Querier;
import com.qingxin.sys.dao.Updater;
import com.qingxin.sys.entity.BaseEntity;
import com.qingxin.sys.mvc.PageParam;
import com.qingxin.sys.mvc.Pager;
import com.qingxin.sys.utils.StringUtils;


@Service
public abstract class BaseService<T extends BaseEntity,ID extends Serializable> implements JdbcSupport {
	@Autowired
    protected IBaseDao<T,ID> dao;
	@Autowired
	private EhCacheCacheManager cacheManager;
	
	/**
	 * 日志记录对象
	 */
	protected Logger logger = LoggerFactory.getLogger(getClass());
	
	/**
	 * 保存一条记录到数据库
	 * @param entity
	 * @return
	 */
	public T save(T entity){
		return dao.save(entity);
	}
	
	/**
	 * 根据主键删除记录
	 * @param id
	 * @return
	 */
	public T delete(ID id){
		return dao.delete(getEntityClass(), id);
	}
	
	
	/**
	 * 根据给定的实体删除对应的数据库记录
	 * @param entity
	 * @return
	 */
	public T delete(T entity){
		return dao.delete(entity);
	}
	
	
	/**
	 * 更新指定记录
	 * @param updater
	 * @return
	 */
	public T update(Updater<T> updater){
		return dao.update(getEntityClass(), updater);
	}
	
	
	/**
	 * 根据主键获取一个实体对象
	 * @param id
	 * @return
	 */
	public T get(ID id) {
		return dao.get(getEntityClass(), id);
	}
	
	
	/**
	 * 根据主键获取一个实体对象
	 * @param id
	 * @param lock
	 * @return
	 */
	public T get(ID id, boolean lock) {
		return dao.get(getEntityClass(), id, lock);
	}
	
	
	/**
	 * 获取安全对象，该对象从缓存中抽离，对其进行修改不影响持久数据
	 * @param id
	 * @return
	 */
	public T getSafeEntity(ID id){
		T entity = dao.get(getEntityClass(), id);
		return dao.evict(entity);
	}
	
	
	
	/**
	 * 从缓存中移除指定对象，可防止意外修改
	 * @param entity
	 * @return
	 */
	public T evict(T entity){
		return dao.evict(entity);
	}
	
	
	/**
	 * 按属性获取指定对象，有多个时返回结果集中的第一条
	 * @param property
	 * @param value
	 * @return
	 */
	public T getByProperty(String property, Object value){
		return dao.getByProperty(getEntityClass(), property, value);
	}
	
	
	/**
	 * 通过HQL查询数据列表
	 * @param hql
	 * @param values
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public List listByHql(String hql, Object... values){
		return dao.listByHql(hql, values);
	}
	
	
	/**
	 * 通过HQL查询指定对象，有多个时返回结果集中的第一条
	 * @param hql
	 * @param values
	 * @return
	 */
	public Object getByHql(String hql, Object... values){
		return dao.getByHql(hql, values);
	}
	
	
	/**
	 * 通过HQL更新数据库
	 * @param hql
	 * @param values
	 * @return
	 */
	public int updateByHql(String hql, Object... values){
		return dao.updateByHql(hql, values);
	}
	
	
	/**
	 * 通过HQL删除数据库记录
	 * @param hql
	 * @param values
	 * @return
	 */
	public int deleteByHql(String hql, Object... values){
		return dao.updateByHql(hql, values);
	}
	
	
	/**
	 * 通过Querier获得列表数据
	 * @param querier
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public List listByQuerier(Querier querier){
		return dao.listByQuerier(querier);
	}
	
	
	
	/**
	 * 通过Querier获得分页数据对象
	 * @param querier
	 * @param pageNo 页码，从1开始
	 * @param pageSize
	 * @return
	 */
	public Pager pageByQuerier(Querier querier, int pageNo, int pageSize){
		return dao.pageByQuerier(querier, pageNo, pageSize);
	}
	
	
	/**
	 * 通过Querier获得列表分页数据
	 * @param querier
	 * @param pageParam
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public List listByQuerier(Querier querier, PageParam pageParam){
		Pager pager = new Pager(pageParam.getPage(), pageParam.getPagesize(), 0);
		querier.setFirstResult(pager.getFirstResult());
		querier.setMaxResults(pager.getPageSize());
		return dao.listByQuerier(querier);
	}
	
	
	/**
	 * 通过Querier获得分页数据对象
	 * @param querier
	 * @param pageParam
	 * @return
	 */
	public Pager pageByQuerier(Querier querier, PageParam pageParam){
		return dao.pageByQuerier(querier, pageParam.getPage(), pageParam.getPagesize());
	}
	
	
	//获取原生JDBC连接，该连接使用完后需要关闭
	@Override
	public Connection getConnection() throws SQLException {
		return dao.getJdbcConnection();
	}
	
	
	@Override
	public void closeConnection(Connection connection) {
		if(connection!=null){
			try {
				connection.close();
			} catch (Exception e) {
			}
		}
	}
	
	
	@Override
	public void closeConnection(Connection connection, Statement statement, ResultSet resultSet) {
		if(resultSet!=null){
			try {
				resultSet.close();
			} catch (Exception e) {
			}
		}
		if(statement!=null){
			try {
				statement.close();
			} catch (Exception e) {
			}
		}
		if(connection!=null){
			try {
				connection.close();
			} catch (Exception e) {
			}
		}
	}
	
	
	/**
	 * 执行指定的SQL语句，如INSERT、UPDATE 或 DELETE
	 * 
	 * @param sql
	 * @param values
	 * @return 执行SQL影响的行数，返回-1表示发生了异常
	 */
	public int executeUpdateSQL(String sql, Object... values) throws SQLException {
		if(values==null){
			values = new Object[]{};
		}
		int result = -1;
		Connection conn = null;
		PreparedStatement pstmt = null;
		try {
			conn = getConnection();
			pstmt = conn.prepareStatement(sql);
			for(int i=0; i<values.length; i++) {
				pstmt.setObject(i+1, values[i]);
			}
			result = pstmt.executeUpdate();
		} catch (SQLException e) {
			throw e;
		} finally {
			closeConnection(conn, pstmt, null);
		}
		return result;
	}
	
	
	
	/**
	 * 获得service对应的实体类
	 * @return
	 */
	@SuppressWarnings("unchecked")
	protected Class<T> getEntityClass(){
		return (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}
	
	
	
	/**
	 * 清除指定缓存
	 * @param cacheName
	 * @param cacheKey
	 */
	public void evictCache(String cacheName, String cacheKey){
		if(StringUtils.isEmpty(cacheName)){
			return;
		}
		try {
			Cache cache = cacheManager.getCache(cacheName);
			if(cache!=null){
				if(StringUtils.isEmpty(cacheKey)){
					//cache.clear();
				}else {
					cache.evict(cacheKey);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
	
	
	/**
	 * 检查表中某个字段的值是否存在
	 * @param fieldname 字段名称
	 * @param fieldvalue 字段值
	 * @return
	 */
	protected boolean isExists(String fieldname, String fieldvalue){
		return isExists(fieldname, fieldvalue, null, null);
	}
	
	
	/**
	 * 检查表中某个字段的值是否存在
	 * @param fieldname 字段名称
	 * @param fieldvalue 字段值
	 * @param exFieldname 排除字段名称
	 * @param exFieldvalue 排除字段值
	 * @return
	 */
	protected boolean isExists(String fieldname, String fieldvalue, String exFieldname, String exFieldvalue){
		Querier querier = Querier.create("select t."+fieldname+" from "+getEntityClass().getName()+" as t where t."+fieldname+" = :fieldvalue");
		querier.setParam("fieldvalue", fieldvalue);
		if(StringUtils.isNotEmpty(exFieldname) && StringUtils.isNotEmpty(exFieldvalue)){
			querier.append(" and t."+exFieldname+" <> :exFieldvalue ");
			querier.setParam("exFieldvalue", exFieldvalue);
		}
		querier.setMaxResults(1);
		List<?> list = listByQuerier(querier);
		return (list!=null && list.size()>0);
	}
	
	
	/**
	 * 获取用于sql的in条件参数，格式：('p1', 'p2', 'p3')
	 * @param collection
	 * @return
	 */
	public String getSqlInParam(Collection<String> collection){
		if(collection==null || collection.size()==0){
			return null;
		}
		return getSqlInParam(collection.toArray(new String[collection.size()]));
	}
	
	
	/**
	 * 获取用于sql的in条件参数，格式：('p1', 'p2', 'p3')
	 * @param array
	 * @return
	 */
	public String getSqlInParam(String[] array){
		if(array==null || array.length==0){
			return null;
		}
		StringBuilder buf = new StringBuilder("(");
		for(int i=0, n=array.length; i<n; i++){
			if(i>0){
				buf.append(", ");
			}
			buf.append("'").append(array[i].replace("'", "")).append("'");
		}
		buf.append(")");
		return buf.toString();
	}
	
	
	/**
	 * 获取用于sql的in条件参数，格式：(p1, p2, p3)
	 * @param array
	 * @return
	 */
	public String getSqlInParam(Integer[] array){
		if(array==null || array.length==0){
			return null;
		}
		String param = Arrays.toString(array).replace('[', '(').replace(']', ')').replaceAll("(\\w+)", "$1");
		return param;
	}
	
	
}
